package com.duanyu.mysecurity.config;

import com.duanyu.mysecurity.handler.*;
import com.duanyu.mysecurity.service.MyUserDetailsService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authorization.AuthorizationDecision;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.session.SessionRegistry;
import org.springframework.security.core.session.SessionRegistryImpl;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.rememberme.PersistentTokenRepository;
import org.thymeleaf.extras.springsecurity6.auth.Authorization;

import java.security.Principal;
import java.util.Collection;

//Security安全配置类
@Configuration
@EnableWebSecurity
public class SecurityConfig {
    @Autowired
    private MyUserDetailsService myUserDetailsService;

    @Autowired
    private PersistentTokenRepository persistentTokenRepository;

    //定义认证逻辑
//    @Bean
//    public UserDetailsManager userDetailsManager(){
//        //1.使用内存数据进行认证
//        InMemoryUserDetailsManager manager = new InMemoryUserDetailsManager();
//        //2.创建两个用户
//        UserDetails user1 = User.withUsername("duanyu").password("123456").authorities("admin").build();
//        UserDetails user2 = User.withUsername("chengwenhui").password("654321").authorities("admin").build();
//
//        //3.将这两个用户添加到内存中
//        manager.createUser(user1);
//        manager.createUser(user2);
//        return manager;
//    }

    //security详细配置
    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http)throws Exception{

        //自定义表单登录
        http.formLogin(form ->{
           form.loginPage("/login.html")    //自定义登录页面
                   .usernameParameter("username")   //表单中的用户名
                   .passwordParameter("password")   //表单中的密码
                   .loginProcessingUrl("/login")    //登录路径，表单向该路径提交，提交后自动执行UserDetailService的方法
//                   .successForwardUrl("/main.html")  //登录成功后，跳转的页面
                   .successHandler(new MyLoginSuccessHandler()) //登录成功后，转到拦截器方法，执行一些想要执行的代码
//                   .failureForwardUrl("/fail.html"); //登陆失败后，跳转的页面
                   .failureHandler(new MyLoginFailureHandler());    //登陆失败后，转到拦截方法，执行java代码
        });

        //权限认证
        http.authorizeHttpRequests(resp ->{
            resp.requestMatchers("/login.html","/fail.html").permitAll();   //不需要认证的资源
            resp.requestMatchers("/css/*.css","/js/*.js","/img/**").permitAll(); //静态资源不需要认证
//            resp.requestMatchers("/reportform/find").hasAnyAuthority("/reportform/find");
//            resp.requestMatchers("/salary/find").hasAnyAuthority("/salary/find");
//            resp.requestMatchers("/staff/find").hasAnyAuthority("/staff/find");
            resp.anyRequest().authenticated();  //其余资源都需要认证

            /**
             * access的参数是一个函数式接口
             * 第一个参数代表认证对象，可以获取认证用户的权限集合
             * 第二个参数代表网络环境，可以获取当前请求的路径
             */
//            resp.anyRequest().access((authentication, requestAuthorizationContext) -> {
//                //获取当前用户的权限
//                Collection<? extends GrantedAuthority> authorities = authentication.get().getAuthorities();
//                //获取请求的url路径
//                String requestURI = requestAuthorizationContext.getRequest().getRequestURI();
//                //将url路径封装为权限对象
//                SimpleGrantedAuthority simpleGrantedAuthority = new SimpleGrantedAuthority(requestURI);
//                //判断用户的权限集合是否包含请求的URl权限
//                boolean contains = authorities.contains(simpleGrantedAuthority);
//                return new AuthorizationDecision(contains);
//            });


        });

        //退出登录
        http.logout(logout -> {
            logout.logoutUrl("/logout") // 退出登录路径
//                    .logoutSuccessUrl("/login.html") // 退出登录后跳转的路径
                    .logoutSuccessHandler(new MyLogoutSuccessHandler()) //退出登陆后执行的拦截器方法
                    .clearAuthentication(true) //清除认证状态，默认为true
                    .invalidateHttpSession(true); // 销毁HttpSession对象，默认为true
        });

        //记住我配置
        http.rememberMe(remember->{
            remember.userDetailsService(myUserDetailsService)   //认证逻辑对象
                    .tokenRepository(persistentTokenRepository) //持久层对象
                    .tokenValiditySeconds(30);          //保存时间，单位是秒
        });

        //配置会话
        http.sessionManagement(session->{
//            session.invalidSessionUrl("/login.html");
            session.invalidSessionStrategy(new MyInvalidSessionStrategy());     //会话失效处理器
            //最大并发会话数，设置单个用户允许同时在线的最大会话数，重新登录的会话会挤掉第一个
            session.maximumSessions(1).maxSessionsPreventsLogin(true);
        });


        //异常处理
        http.exceptionHandling(exception->{
            exception.accessDeniedHandler(new MyAccessDeniedHandler());
        });

        //关闭csrf防护
        http.csrf(AbstractHttpConfigurer::disable);

        return http.build();


    }

    //密码编码器
    @Bean
    public PasswordEncoder passwordEncoder(){
        return new BCryptPasswordEncoder();
    }

    //主动踢人下线的方法
    @Bean
    public SessionRegistry sessionRegistry(){
        return new SessionRegistryImpl();
    }

}
